package com.jtpay.ysfproductionprocess.http.retrofit;

import android.content.Context;
import android.content.Intent;
import android.net.ParseException;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import com.google.gson.JsonParseException;
import com.jtpay.ysfproductionprocess.R;
import com.jtpay.ysfproductionprocess.enums.LogLevelEnum;
import com.jtpay.ysfproductionprocess.enums.LogModuleEnum;
import com.jtpay.ysfproductionprocess.http.dataStructure.BasicResponse;
import com.jtpay.ysfproductionprocess.utils.AlarmSoundManager;
import com.jtpay.ysfproductionprocess.utils.LogUtil;
import com.jtpay.ysfproductionprocess.utils.PayContext;
import com.jtpay.ysfproductionprocess.utils.manager.ToastUtil;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import org.json.JSONException;
import retrofit2.HttpException;

import java.io.InterruptedIOException;
import java.net.ConnectException;
import java.net.UnknownHostException;

import static com.jtpay.ysfproductionprocess.http.retrofit.RetrofitObserver.ExceptionReason.*;
import static com.jtpay.ysfproductionprocess.utils.ApiConstant.HTTP_SUCCESS;
import static com.jtpay.ysfproductionprocess.utils.ApiConstant.HTTP_VIRTUAL_CARD_FAILURE;
import static com.jtpay.ysfproductionprocess.utils.PayContext.*;

public class RetrofitObserver<T extends BasicResponse> implements Observer<T> {
    private Context mContext;

    protected RetrofitObserver(Context context) {
        mContext = context;
    }

    @Override
    public void onSubscribe(Disposable d) {
        LogUtil.log("onSubscribe = " + d.toString());
    }

    @Override
    public void onNext(T response) {
        switch (response.getFlag()) {
            case HTTP_SUCCESS:
                onSuccess(response);
                break;
            case HTTP_VIRTUAL_CARD_FAILURE:
                onHeaderFail(response);
                break;
            default:
                onFail(response);
                break;
        }
    }

    /**
     * 请求数据成功 且响应码为200
     *
     * @param response 服务器返回的数据
     */
    public void onSuccess(T response) {
        PayContext.resetErrorCount();
        if (AlarmSoundManager.getInstance().isPlaying()) {
            AlarmSoundManager.getInstance().stop();
        }
    }

    /**
     * 请求数据成功 且响应码为200 需要重新获取header
     *
     * @param response 服务器返回的数据
     */
    private void onHeaderFail(final T response) {
        LogUtil.log("onHeaderFail = " + response.toString());
        LogUtil.logUpload(mContext, "onHeaderFail = " + response.toString(), LogModuleEnum.DECRYPT_INFO.message, LogLevelEnum.LOG_ERROR.message);
        PayContext.API_ERROR_COUNT -= 1;
        if (PayContext.API_ERROR_COUNT < 0) {
            sendMsg(mContext.getString(R.string.api_error_count_max_tips));
            LogUtil.logUpload(mContext, mContext.getString(R.string.api_error_count_max_tips), LogModuleEnum.GET_HEADER.message, LogLevelEnum.LOG_ERROR.message);
            AlarmSoundManager.getInstance().play();
            return;
        }
        Intent intent = new Intent(ACTION_UNION_PAY_GET_HEADER);
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
    }

    /**
     * 服务器返回数据，但响应码不为200
     *
     * @param response 服务器返回的数据
     */
    public void onFail(T response) {
        LogUtil.log("onFail = " + response.toString());
        PayContext.API_ERROR_COUNT -= 1;
        String message = response.getMsg();
        if (!TextUtils.isEmpty(message)) {
            ToastUtil.showShort(message);
        }
        resumeTaskApi();
    }

    @Override
    public void onError(Throwable e) {
        LogUtil.log("RetrofitObserver onError " + e.getMessage());
        PayContext.API_ERROR_COUNT -= 1;
        if (e instanceof HttpException) {     //   HTTP错误
            onException(BAD_NETWORK);
        } else if (e instanceof ConnectException
                || e instanceof UnknownHostException) {   //   连接错误
            onException(CONNECT_ERROR);
        } else if (e instanceof InterruptedIOException) {   //  连接超时
            onException(CONNECT_TIMEOUT);
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {   //  解析错误
            onException(PARSE_ERROR);
        } else {
            onException(UNKNOWN_ERROR);
        }
        resumeTaskApi();
    }

    /**
     * goto task api
     */
    private void resumeTaskApi() {
        if (PayContext.API_ERROR_COUNT < 0) {
            sendMsg(mContext.getString(R.string.api_error_count_max_tips));
            LogUtil.logUpload(mContext, mContext.getString(R.string.api_error_count_max_tips), LogModuleEnum.GET_HEADER.message, LogLevelEnum.LOG_ERROR.message);
            AlarmSoundManager.getInstance().play();
            return;
        }
        ToastUtil.showShort(R.string.response_return_error);
        Intent intent = new Intent(ACTION_CONTINUE_TASK);
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
    }

    /**
     * 请求异常
     *
     * @param reason ExceptionReason
     */
    private void onException(ExceptionReason reason) {
        switch (reason) {
            case CONNECT_ERROR:
                ToastUtil.showShort(R.string.connect_error);
                break;
            case CONNECT_TIMEOUT:
                ToastUtil.showShort(R.string.connect_timeout);
                break;
            case BAD_NETWORK:
                ToastUtil.showShort(R.string.bad_network);
                break;
            case PARSE_ERROR:
                ToastUtil.showShort(R.string.parse_error);
                break;
            case UNKNOWN_ERROR:
            default:
                ToastUtil.showShort(R.string.unknown_error);
                break;
        }
    }

    @Override
    public void onComplete() {
        LogUtil.log("RetrofitObserver onComplete ");
    }

    public enum ExceptionReason {
        CONNECT_ERROR, CONNECT_TIMEOUT, BAD_NETWORK, PARSE_ERROR, UNKNOWN_ERROR
    }

    /**
     * @param content send log content
     */
    private void sendMsg(String content) {
        Intent intent = new Intent(ACTION_UNION_PAY_SHOW_LOG);
        intent.putExtra(BROADCAST_CONTENT_KEY, content);
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
    }
}
